using System;
using System.Collections;
using System.Data;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.ScriptEngine;
using PHSRAG.Security.Enumerations;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.FormsManagement
{
    /// <summary>
    /// FormEditor page helps in managing QuestionnaireItems, dependencies among questionnaire items, documents, question study persons and scripts.
    /// </summary>
    public partial class FormEditor : BasePage
    {
        #region Constants

        private const string ChildQuestionsKey = "childQuestions_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string ColumnChildQuestion = "ChildQuestion";
        private const string ColumnDocumentType = "DocumentType";
        private const string ColumnId = "Id";
        private const string ColumnIdWhenLoaded = "IdWhenLoaded";
        private const string ColumnIndent = "Indent";
        private const string ColumnItemName = "ItemName";
        private const string ColumnItemValue = "ItemValue";
        private const string ColumnMarkForDeletion = "MarkForDeletion";
        private const string ColumnName = "Name";
        private const string ColumnOrder = "Order";
        private const string ColumnParentQuestion = "ParentQuestion";
        private const string ColumnParentValue = "ParentValue";
        private const string ColumnRequired = "Required";
        private const string ColumnSNo = "SNo";
        private const string ColumnText = "Text";
        private const string ColumnType = "Type";
        private const string ColumnValidationMessage = "ValidationMessage";
        private const string CurrentPageIndexKey = "currentPageIndexKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string DependencySourceKey = "DependencySourceKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string DocumentSourceKey = "DocumentSourceKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string FormEditorPageKey = "formEditorPageKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string GridSourceKey = "gridSourceKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string ParentQuestionsKey = "parentQuestions_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string ScriptSourceKey = "ScriptSourceKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string SelectedQuestionnaireIdKey = "SelectedQuestionnaireIdKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string SelectedQuestionnaireVersionIdKey = "SelectedQuestionnaireVersionIdKey_643F1B7C-ECFC-4238-906A-A83CF7318527";
        private const string SelectedQuestionnaireVersionKey = "SelectedQuestionnaireVersionKey_643F1B7C-ECFC-4238-906A-A83CF7318527";

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy applicationCachePolicy;
        private ICachePolicy cachePolicy;

        private DataTable dependencySource;
        private DataTable documentSource;
        private DataView itemsSourceView;
        private ICachePolicy pageCachePolicy;
        private DataTable pagedResults;
        private DataTable scriptSource;
        private ArrayList scriptTypes;
        private int selectedQuestionnaireID;
        private int selectedQuestionnaireVersionID;
        private QuestionnaireVersion selectedVersion;

        #endregion

        #region Properties

        /// <summary>
        /// DataSource for parent questions displayed in the grid. 
        /// </summary>
        protected ListItemCollection ParentItemsForDependancy
        {
            get
            {
                ListItemCollection collection = (ListItemCollection) pageCachePolicy.GetCachedObject(ParentQuestionsKey);
                if (collection == null)
                {
                    collection = new ListItemCollection();
                    collection.Add(new ListItem("", "0"));
                    foreach (QuestionnaireItem item in selectedVersion.Items)
                    {
                        //Exclude Label, Textbox and DropDownList questions as they do not act as parent questions to other questions
                        if (item.Type != QuestionnaireItem.DropDownListItemType && item.Type != QuestionnaireItem.TextBoxItemType && item.Type != QuestionnaireItem.LabelItemType)
                        {
                            collection.Add(new ListItem(item.Name, item.Id.ToString()));
                        }
                    }
                    pageCachePolicy.Cache(ParentQuestionsKey, collection);
                }
                return collection;
            }
        }


        /// <summary>
        /// Gets the QuestionnaireItems for the selected QuestionnaireVersion
        /// </summary>
        protected ListItemCollection ChildItemsForDependancy
        {
            get
            {
                ListItemCollection collection = (ListItemCollection) pageCachePolicy.GetCachedObject(ChildQuestionsKey);
                if (collection == null)
                {
                    collection = new ListItemCollection();
                    collection.Add(new ListItem("", "0"));
                    foreach (QuestionnaireItem item in selectedVersion.Items)
                    {
                        collection.Add(new ListItem(item.Name, item.Id.ToString()));
                    }
                    pageCachePolicy.Cache(ChildQuestionsKey, collection);
                }
                return collection;
            }
        }


        /// <summary>
        /// Gets the document/attachment types codes from the cache
        /// </summary>
        protected ArrayList DocumentTypes
        {
            get
            {
                string moduleName = Enum.GetName(typeof (ModuleBit), selectedVersion.Questionnaire.ModuleType);

                ArrayList docTypes = ((RefCodes) applicationCachePolicy.GetCachedObject(RefCodes.CacheKey)).GetSortedRefCodes(Constants.AttachmentType.Domain,
                    (moduleName == InsightUtilities.Constants.Modules.Animals) ? Constants.AttachmentType.AnimalsOrderAttribute : Constants.AttachmentType.HumansOrderAttribute);

                moduleName = moduleName.ToUpper();
                for (int i = docTypes.Count - 1; i >= 0; i--)
                {
                    RefCode code = (RefCode) docTypes[i];
                    if (code[moduleName] != "Y")
                    {
                        docTypes.Remove(code);
                    }
                }
                RefCode emptyCode = new RefCode(cachePolicy, "", "", "", 'N', null);
                docTypes.Insert(0, emptyCode);
                return docTypes;
            }
        }


        /// <summary>
        /// Gets the QuestionDocuments for the selected QuestionnaireVersion
        /// </summary>
        protected ArrayList QuestionDocuments
        {
            get { return selectedVersion.Documents; }
        }


        /// <summary>
        /// Gets or sets the scripts for the selected QuestionnaireVersion
        /// </summary>
        private Hashtable Scripts
        {
            get { return selectedVersion.Scripts; }
            set { selectedVersion.Scripts = value; }
        }


        /// <summary>Gets or sets current page index for the grid</summary>
        private int CurrentPageIndex
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(FormEditorPageKey) as Hashtable;
                return (h == null || h[CurrentPageIndexKey] == null) ? 0 : (int) h[CurrentPageIndexKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(FormEditorPageKey) as Hashtable ?? new Hashtable();
                h[CurrentPageIndexKey] = value;
                versionItems.CurrentPageIndex = value;
                pageCachePolicy.Cache(FormEditorPageKey, h);
            }
        }

        #endregion

        #region Events (page)

        /// <summary>
        /// On first page load, data is pulled out of the incoming cache and is maintained
        /// by the page. On subsequent page loads, the data stored in the page cache is used.
        /// Displays all the questions, dependencies, documents and scripts that form the selected version
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                if (header.ModuleName == InsightUtilities.Constants.Modules.Admin)
                {
                    adminHumansSubNavigation.Visible = true;
                    coiSubNavigation.Visible = false;
                }
                else if (header.ModuleName == InsightUtilities.Constants.Modules.COI)
                {
                    adminHumansSubNavigation.Visible = false;
                    coiSubNavigation.Visible = true;
                }

                breadCrumb.Add(" Forms Management",
                    Settings.GetKeyValue("SubNavigation.Admin.humansURL", ""),
                    Settings.GetKeyValue("BreadCrumb.SummaryPageLevel", 1));

                annunciator.Message = string.Empty;

                scriptTypes = ((RefCodes) applicationCachePolicy.GetCachedObject(RefCodes.CacheKey)).GetRefCodes(Constants.ScriptType.Domain);

                if (!Page.IsPostBack && postbackGuard.IsValid)
                {
                    Hashtable incomingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
                    if (incomingData != null)
                    {
                        selectedQuestionnaireID = Convert.ToInt32(incomingData[Keys.QuestionnaireIdKey]);
                        pageCachePolicy.Cache(SelectedQuestionnaireIdKey, incomingData[Keys.QuestionnaireIdKey]);
                        selectedQuestionnaireVersionID = Convert.ToInt32(incomingData[Keys.QuestionnaireVersionIdKey]);
                        pageCachePolicy.Cache(SelectedQuestionnaireVersionIdKey, incomingData[Keys.QuestionnaireVersionIdKey]);

                        //If arrived at from Versions page, then set the grid to show the 1st page.
                        if (incomingData.ContainsKey(Keys.FromParentPage))
                        {
                            CurrentPageIndex = 0;
                            incomingData.Remove(Keys.FromParentPage);
                        }

                        pageCachePolicy.UnCache(Keys.IncomingDataKey);

                        pageCachePolicy.UnCache(ParentQuestionsKey);
                        pageCachePolicy.UnCache(ChildQuestionsKey);
                    }
                    else
                    {
                        selectedQuestionnaireID = Convert.ToInt32(pageCachePolicy.GetCachedObject(SelectedQuestionnaireIdKey));
                        selectedQuestionnaireVersionID = Convert.ToInt32(pageCachePolicy.GetCachedObject(SelectedQuestionnaireVersionIdKey));
                    }

                    Hashtable questionnairesList = (Hashtable) cachePolicy.GetCachedObject(Keys.QuestionnaireObjectsKey);
                    Questionnaire questionnaire = (Questionnaire) questionnairesList[selectedQuestionnaireID];
                    selectedVersion = questionnaire.GetQuestionnaireVersionById(selectedQuestionnaireVersionID);
                    questionnaireName.Text = questionnaire.Name;
                    questionnaireVersion.Text = selectedVersion.Version.ToString();

                    BindGrid();


                    CreateDependencySource();
                    LoadDependencySource();
                    BindDependencyGrid();

                    CreateDocumentSource();
                    LoadDocumentSource();
                    BindDocumentGrid();

                    CreateScriptSource();
                    LoadScriptSource();
                    BindScriptGrid();

                    pageCachePolicy.Cache(DependencySourceKey, dependencySource);
                    pageCachePolicy.Cache(DocumentSourceKey, documentSource);
                    pageCachePolicy.Cache(ScriptSourceKey, scriptSource);

                    //Clearing the Parent and Child questions cache. 
                    //If question names are modified and then the cache needs to be updated with the new names.
                    ListItemCollection collection = pageCachePolicy.GetCachedObject(ParentQuestionsKey) as ListItemCollection;
                    if (collection != null)
                    {
                        pageCachePolicy.UnCache(ParentQuestionsKey);
                    }

                    collection = (ListItemCollection) pageCachePolicy.GetCachedObject(ChildQuestionsKey);
                    if (collection != null)
                    {
                        pageCachePolicy.UnCache(ChildQuestionsKey);
                    }
                }
                else
                {
                    selectedQuestionnaireID = Convert.ToInt32(pageCachePolicy.GetCachedObject(SelectedQuestionnaireIdKey));
                    selectedQuestionnaireVersionID = Convert.ToInt32(pageCachePolicy.GetCachedObject(SelectedQuestionnaireVersionIdKey));
                    Hashtable questionnairesList = (Hashtable) cachePolicy.GetCachedObject(Keys.QuestionnaireObjectsKey);
                    Questionnaire questionnaire = (Questionnaire) questionnairesList[selectedQuestionnaireID];
                    selectedVersion = questionnaire.GetQuestionnaireVersionById(selectedQuestionnaireVersionID);
                    Hashtable h = pageCachePolicy.GetCachedObject(FormEditorPageKey) as Hashtable;
                    itemsSourceView = (DataView) h[GridSourceKey];

                    dependencySource = (DataTable) pageCachePolicy.GetCachedObject(DependencySourceKey);
                    UpdateDependencySource();
                    documentSource = (DataTable) pageCachePolicy.GetCachedObject(DocumentSourceKey);
                    UpdateDocumentSource();
                    scriptSource = (DataTable) pageCachePolicy.GetCachedObject(ScriptSourceKey);
                    UpdateScriptSource();
                }

                ManagePagination();

                if (selectedVersion.IsDeployed)
                {
                    deleteItem.Enabled = false;
                    addQuestionnaireItem.Enabled = false;

                    deleteDependency.Enabled = false;
                    deleteDocument.Enabled = false;
                    deleteScript.Enabled = false;

                    addDependency.Enabled = false;
                    addDocument.Enabled = false;
                    addScript.Enabled = false;
                }

                if (deleteConfirmation.Value.ToLower() == "true")
                {
                    DeleteItem(true);
                }
                deleteConfirmation.Value = string.Empty;
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load the page.";
            }
            finally
            {
                if (coiSubNavigation.Visible)
                {
                    coiSubNavigation.SelectedLink = "Forms Management";
                    coiSubNavigation.AccessLevel = ((UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey)).ModuleRoleBitmask;
                }
            }
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Page Init
        /// </summary>
        /// <param name="e">Arguments associated with the event.</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            applicationCachePolicy = (Policy.ICachePolicy) Application[Policy.Names.ApplicationCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.topPager.FirstPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnFirstPage);
            this.topPager.PreviousPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnPreviousPage);
            this.topPager.NextPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnNextPage);
            this.topPager.LastPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnLastPage);
            this.bottomPager.FirstPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnFirstPage);
            this.bottomPager.PreviousPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnPreviousPage);
            this.bottomPager.NextPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnNextPage);
            this.bottomPager.LastPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnLastPage);

            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.versionItems.ItemCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnVersionItemsItemCommand);
            this.versionItems.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnVersionItemsItemDataBound);
            this.moveItemUp.Click += new System.Web.UI.ImageClickEventHandler(this.OnMoveItemUp);
            this.moveItemDown.Click += new System.Web.UI.ImageClickEventHandler(this.OnMoveItemDown);
            this.Load += new System.EventHandler(this.OnPageLoad);

            this.dependencyItems.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnDependencyItemsItemDataBound);
            this.documentItems.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnDocumentItemsItemDataBound);
            this.scriptItems.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnScriptItemsItemDataBound);
        }

        #endregion

        #region Events (controls)

        /// <summary>
        /// Occurs when the FirstPage hyperlink is clicked on the pager.
        /// The grid is reloaded with the data pertaining to the first page.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnFirstPage(object sender, CommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                CurrentPageIndex = 0;
                BindGrid();
                ManagePagination();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while loading the first page.";
            }
        }


        /// <summary>
        /// Occurs when the LastPage hyperlink is clicked on the pager.
        /// The grid is reloaded with the data pertaining to the last page.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnLastPage(object sender, CommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                int lastPageIndex = topPager.PageCount - 1;
                CurrentPageIndex = lastPageIndex;
                BindGrid();
                ManagePagination();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while loading the last page.";
            }
        }


        /// <summary>
        /// Occurs when the NexttPage hyperlink is clicked on the pager.
        /// The grid is reloaded with the data pertaining to the next page.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNextPage(object sender, CommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                ++CurrentPageIndex;
                BindGrid();
                ManagePagination();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while loading the next page.";
            }
        }


        /// <summary>
        /// Occurs when the PreviousPage hyperlink is clicked on the pager.
        /// The grid is reloaded with the data pertaining to the previous page.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnPreviousPage(object sender, CommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                --CurrentPageIndex;
                BindGrid();
                ManagePagination();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while loading the previous page.";
            }
        }


        /// <summary>
        /// Stores Id's of selected questionnaire, version, item objects and also the type of the question in the cache 
        /// and redirects the user to ItemEditor page.
        /// </summary>
        /// <param name="source">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnVersionItemsItemCommand(object source, DataGridCommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    int id = int.Parse(((Label) e.Item.FindControl("questionnaireItemID")).Text);

                    Hashtable outgoingData = new Hashtable();
                    outgoingData.Add(Keys.QuestionnaireIdKey, selectedQuestionnaireID);
                    outgoingData.Add(Keys.QuestionnaireVersionIdKey, selectedQuestionnaireVersionID);
                    outgoingData.Add(Keys.QuestionnaireItemIdKey, id);
                    outgoingData.Add(Keys.QuestionnaireItemTypeKey, selectedVersion.GetQuestionnaireItemById(id).Type);
                    pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
                    Page.Response.Redirect(e.CommandName, false);
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while redirecting to the Form Editor page.";
            }
        }


        /// <summary>
        /// Interchanges the order of the selected question with that of the preceding question and binds the grid.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnMoveItemUp(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                for (int i = 0; i < versionItems.Items.Count; ++i)
                {
                    if (((RadioButton) versionItems.Items[i].FindControl("selectItem")).Checked)
                    {
                        int id = int.Parse(((Label) versionItems.Items[i].FindControl("questionnaireItemID")).Text);
                        if (i == 0 && versionItems.CurrentPageIndex == 0)
                        {
                            return;
                        }

                        int j = 1;
                        for (; j < itemsSourceView.Count; ++j)
                        {
                            if (id == Convert.ToInt32(itemsSourceView[j][ColumnId]))
                            {
                                break;
                            }
                        }
                        int previousRowId = Convert.ToInt32(itemsSourceView[j - 1][ColumnId]);
                        QuestionnaireItem previousQuestionnaireItem = selectedVersion.GetQuestionnaireItemById(previousRowId);
                        QuestionnaireItem currentQuestionnaireItem = selectedVersion.GetQuestionnaireItemById(id);
                        selectedItemTracker.Value = id.ToString();
                        int currentQuestionnaireItemOrder = currentQuestionnaireItem.Order;
                        currentQuestionnaireItem.Order = previousQuestionnaireItem.Order;
                        previousQuestionnaireItem.Order = currentQuestionnaireItemOrder;
                        selectedVersion.Save(DataAccess.ConnectionString);
                        break;
                    }
                }
                BindGrid();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while reordering questions.";
            }
        }


        /// <summary>
        /// Interchanges the order of the selected question with that of the following question and binds the grid.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnMoveItemDown(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }
                for (int i = 0; i < versionItems.Items.Count; ++i)
                {
                    if (((RadioButton) versionItems.Items[i].FindControl("selectItem")).Checked)
                    {
                        int id = int.Parse(((Label) versionItems.Items[i].FindControl("questionnaireItemID")).Text);
                        if (i == versionItems.Items.Count - 1 && versionItems.CurrentPageIndex == (topPager.PageCount - 1))
                        {
                            return;
                        }

                        int j = 0;
                        for (; j < itemsSourceView.Count - 1; ++j)
                        {
                            if (id == Convert.ToInt32(itemsSourceView[j][ColumnId]))
                            {
                                break;
                            }
                        }
                        int nextRowId = Convert.ToInt32(itemsSourceView[j + 1][ColumnId]);
                        QuestionnaireItem nextQuestionnaireItem = selectedVersion.GetQuestionnaireItemById(nextRowId);
                        QuestionnaireItem currentQuestionnaireItem = selectedVersion.GetQuestionnaireItemById(id);
                        selectedItemTracker.Value = id.ToString();
                        int currentQuestionnaireItemOrder = currentQuestionnaireItem.Order;
                        currentQuestionnaireItem.Order = nextQuestionnaireItem.Order;
                        nextQuestionnaireItem.Order = currentQuestionnaireItemOrder;
                        selectedVersion.Save(DataAccess.ConnectionString);
                        break;
                    }
                }
                BindGrid();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while reordering questions.";
            }
        }


        /// <summary>
        /// Adds a call to a javascript function which would allow the user to select only one radio button.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnVersionItemsItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    RadioButton selectItem = (RadioButton) e.Item.FindControl("selectItem");
                    selectItem.Attributes.Add("OnClick", "javascript:RestrictItemSelection('" + selectItem.ClientID + "')");

                    if (selectedItemTracker.Value == ((Label) e.Item.FindControl("questionnaireItemID")).Text)
                    {
                        selectedItemTracker.Value = selectItem.ClientID;
                        selectItem.Checked = true;
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while loading the questions grid";
            }
        }


        /// <summary>
        /// Resets the subnavigation selected link before the header or the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                adminSubNavigation.Reset();
                adminHumansSubNavigation.Reset();
                coiSubNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }


        /// <summary>
        /// Updates dependencies, question documents and script and saves all the changes made to the questionnaire version
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnSaveClick(object sender, EventArgs e)
        {
            try
            {
                if (ValidateData())
                {
                    UpdateDependencies();
                    UpdateDocuments();
                    UpdateScripts();
                    selectedVersion.Save(DataAccess.ConnectionString);
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Error occurred while saving questions";
            }
        }


        /// <summary>
        /// Ignores all the changes made and redirects the user to the Questionnaire Versions page
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnCancelClick(object sender, EventArgs e)
        {
            try
            {
                Response.Redirect(Settings.GetKeyValue("SubNavigation.Admin.Humans.VersionsURL", "Version.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }


        /// <summary>
        /// Redirects the user to the preview page
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnPreviewQuestionnaireClick(object sender, EventArgs e)
        {
            try
            {
                Hashtable outgoingData = new Hashtable();
                outgoingData.Add(Keys.QuestionnaireIdKey, selectedQuestionnaireID);
                outgoingData.Add(Keys.QuestionnaireVersionIdKey, selectedQuestionnaireVersionID);
                pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);

                Response.Redirect(Settings.GetKeyValue("SubNavigation.Admin.Humans.QuestionnairePreviewURL", "QuestionnairePreview.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }


        /// <summary>
        /// Redirects the user to a page which allows him to add a new Questionnaire Item
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnAddQuestionnaireItemClick(object sender, EventArgs e)
        {
            try
            {
                //uncache the cached list of parent and child questions
                pageCachePolicy.UnCache(ParentQuestionsKey);
                pageCachePolicy.UnCache(ChildQuestionsKey);

                Hashtable outgoingData = new Hashtable();
                outgoingData.Add(Keys.QuestionnaireIdKey, selectedQuestionnaireID);
                outgoingData.Add(Keys.QuestionnaireVersionIdKey, selectedQuestionnaireVersionID);
                pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);

                Response.Redirect(Settings.GetKeyValue("SubNavigation.Admin.Humans.AddItemURL", "AddItem.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }


        /// <summary>
        /// Checks if there are any dependencies on the question being deleted.
        /// If so, prompts the user before deleting. If not, deletes the question.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnDeleteItemClick(object sender, EventArgs e)
        {
            try
            {
                //uncache the cached list of parent and child questions
                pageCachePolicy.UnCache(ParentQuestionsKey);
                pageCachePolicy.UnCache(ChildQuestionsKey);

                DeleteItem(false);
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to delete the question.";
            }
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Enables or Disables links to other pages of the grid on the pager controls
        /// </summary>
        private void ManagePagination()
        {
            int currentPageIndex = CurrentPageIndex;
            versionItems.CurrentPageIndex = currentPageIndex;

            int startIndex = currentPageIndex*versionItems.PageSize;
            bottomPager.FirstRecord = topPager.FirstRecord = startIndex + 1;

            int lastRecord = itemsSourceView.Count;
            bottomPager.LastRecord = topPager.LastRecord =
                Math.Min(startIndex + versionItems.PageSize, lastRecord);

            int pageCount = (topPager.RecordCount/versionItems.PageSize) +
                (((topPager.RecordCount%versionItems.PageSize) == 0) ? 0 : 1);
            bottomPager.PageCount = topPager.PageCount = pageCount;
            bottomPager.CurrentPage = topPager.CurrentPage = currentPageIndex + 1;

            bottomPager.EnableFirstPage = topPager.EnableFirstPage =
                bottomPager.EnablePreviousPage = topPager.EnablePreviousPage =
                    (versionItems.CurrentPageIndex != 0);

            bottomPager.EnableLastPage = topPager.EnableLastPage =
                bottomPager.EnableNextPage = topPager.EnableNextPage =
                    ((topPager.PageCount != 0) && (versionItems.CurrentPageIndex != (topPager.PageCount - 1)));
        }


        /// <summary>
        /// Binds all the questionnaire items to the datagrid. To display the items sorted by their order, 
        /// a DataView is constructed out of the hashtable holding the questionnaire items and this view 
        /// is set as the datasource for the datagrid
        /// 
        /// The itemsSource DataTable is not cached because the user can come to this page after adding a question
        /// and having the itemsSource in the cache would require it to be updated from the page where a question is being added.
        /// 
        /// The default view of the itemsSource is ordered on the "Order" column and this  view is cached because the view is required 
        /// while reordering the questions. The view helps especially in situations where the user selects either the first or last record
        /// displayed in a datagrid page. The view helps in finding out 
        /// 1. the record that comes prior to the first record in the page
        /// 2. the record that comes next to the last record in the page
        /// </summary>
        private void BindGrid()
        {
            DataTable itemsSource = new DataTable();
            itemsSource.Columns.Add(ColumnId);
            itemsSource.Columns.Add(ColumnName);
            itemsSource.Columns.Add(ColumnText);
            itemsSource.Columns.Add(ColumnType);
            itemsSource.Columns.Add(ColumnOrder, typeof (int));

            foreach (QuestionnaireItem item in selectedVersion.Items)
            {
                DataRow row = itemsSource.NewRow();
                row[ColumnId] = item.Id;
                row[ColumnName] = item.Name;
                row[ColumnText] = item.Text;
                row[ColumnType] = item.Type;
                row[ColumnOrder] = item.Order;
                itemsSource.Rows.Add(row);
            }

            versionItems.VirtualItemCount = bottomPager.RecordCount =
                topPager.RecordCount = itemsSource.Rows.Count;

            versionItems.DataSource = GetQuestionsForGridPage(itemsSource, CurrentPageIndex*versionItems.PageSize, versionItems.PageSize);
            versionItems.DataBind();
        }


        /// <summary>
        /// Gets the questions that need to be displayed for a specific page of the grid
        /// </summary>
        /// <param name="source">The source of data for the grid</param>
        /// <param name="startIndex">The grid's current page first record index</param>
        /// <param name="pageSize">The number of records displayed in a grid's page</param>
        /// <returns></returns>
        private DataTable GetQuestionsForGridPage(DataTable source, int startIndex, int pageSize)
        {
            pagedResults = source.Clone();

            itemsSourceView = source.DefaultView;
            itemsSourceView.Sort = "Order";


            Hashtable h = pageCachePolicy.GetCachedObject(FormEditorPageKey) as Hashtable ?? new Hashtable();
            h[GridSourceKey] = itemsSourceView;
            pageCachePolicy.Cache(FormEditorPageKey, h);

            for (int m = startIndex, endIndex = Math.Min(itemsSourceView.Count, startIndex + pageSize); m < endIndex; ++m)
            {
                pagedResults.ImportRow(itemsSourceView[m].Row);
            }
            return pagedResults;
        }


        /// <summary>
        /// Deletes the selected questionnaire item.
        /// 
        /// If deleteConfirmed is false, then this method checks if there are any
        /// dependencies on the question being deleted. If so, returns back to the 
        /// client with a confirmation message. If not, deletes the question.
        /// 
        /// If deletedConfirmed is true, then deletes the question and its dependencies.
        /// 
        /// </summary>
        /// <param name="deleteConfirmed">if set to true, then the question along with all the dependencies are deleted. If not, then all the dependancies 
        /// for the question being deleted are listed out and shown to user.</param>
        private void DeleteItem(bool deleteConfirmed)
        {
            for (int i = 0; i < versionItems.Items.Count; i++)
            {
                if (((RadioButton) versionItems.Items[i].FindControl("selectItem")).Checked)
                {
                    QuestionnaireItem item = selectedVersion.GetQuestionnaireItemById(int.Parse(((Label) versionItems.Items[i].FindControl("questionnaireItemID")).Text));
                    if (!deleteConfirmed)
                    {
                        string msg = GetItemDependencies(item);
                        //check for dependencies and pop the msg
                        if (msg.Length > 0)
                        {
                            string script = "\n<script language=\"JavaScript\" id=\"OnItemDelete\">\n" +
                                "var res = confirm('" + msg + "');" +
                                    "if (res) { " +
                                        "var deleteConfirmation = document.getElementById('deleteConfirmation');" +
                                            "deleteConfirmation.value = res;" +
                                                "document.forms[0].submit(); }" +
                                                    "</script>";

                            //Check whether the script is already registered
                            if (!ClientScript.IsClientScriptBlockRegistered("OnItemDelete"))
                            {
                                ClientScript.RegisterStartupScript(GetType(), "OnItemDelete", script);
                            }
                            break;
                        }
                        deleteConfirmed = true;
                    }

                    item.MarkForDelete = true;
                    //delete the dependency between the deleted question and all its children
                    foreach (QuestionnaireItem qi in selectedVersion.Items)
                    {
                        if (qi.ParentName == item.Name)
                        {
                            qi.ParentName = string.Empty;
                            qi.ParentValue = string.Empty;
                        }
                    }
                    selectedItemTracker.Value = string.Empty;
                    selectedVersion.Save(DataAccess.ConnectionString);
                    selectedVersion.Documents = null;
                    if (versionItems.Items.Count == 1 && CurrentPageIndex > 0)
                    {
                        CurrentPageIndex -= 1;
                    }

                    BindGrids();
                    BindGrid();
                    ManagePagination();
                }
            }
        }


        /// <summary>
        /// Returns a message listing out all the dependencies for the item passed in as a parameter
        /// </summary>
        /// <param name="item">QuestionnaireItem whose dependencies have to be listed out</param>
        /// <returns>A string with all the dependent document types, study person roles and child questions</returns>
        private string GetItemDependencies(QuestionnaireItem item)
        {
            RefCodes refCodes = (RefCodes) applicationCachePolicy.GetCachedObject(RefCodes.CacheKey);
            StringBuilder docMessage = new StringBuilder();
            //get the question documents dependent on the question being deleted
            foreach (QuestionDocument qd in selectedVersion.Documents)
            {
                if (qd.ItemName == item.Name)
                {
                    docMessage.Append(refCodes.GetRefCode(qd.Type).Meaning + ", ");
                }
            }
            int i = docMessage.ToString().Length;
            if (i > 0)
            {
                docMessage = docMessage.Remove(i - 2, 2); //2 for the extra ',' and space following the last question name in the string
                docMessage.Insert(0, "Documents - ");
            }

            //get the child questions of the deleted question
            StringBuilder qiMessage = new StringBuilder();
            foreach (QuestionnaireItem qi in selectedVersion.Items)
            {
                if (qi.ParentName == item.Name)
                {
                    qiMessage.Append(qi.Name + ", ");
                }
            }
            i = qiMessage.ToString().Length;
            if (i > 0)
            {
                qiMessage = qiMessage.Remove(i - 2, 2); //2 for the extra ',' and space following the last question name in the string
                qiMessage.Insert(0, "Child questions - ");
            }

            //Form a single message that includes the above messages for parent-child relationships and dependent question documents
            StringBuilder retValue = new StringBuilder();
            if (docMessage.Length > 0)
            {
                retValue.Append("\\r\\n" + docMessage);
            }
            if (qiMessage.Length > 0)
            {
                retValue.Append("\\r\\n" + qiMessage);
            }
            return (retValue.Length > 0) ? string.Format("The selected question has the following dependencies:\\r\\n{0}\\r\\n\\r\\nDeleting the question will delete all the dependencies listed above.\\r\\nClick \\'OK\\' to continue.", retValue)
                : string.Empty;
        }


        /// <summary>
        /// Reloads the data and binds all the grids except Scripts
        /// 
        /// Whenever a question is deleted, all its dependencies and the documents tied 
        /// to it are also removed and hence, these grids have to be
        /// reloaded. Scirpts are tied to a version and not to any specific question.
        /// </summary>
        private void BindGrids()
        {
            dependencySource = (DataTable) pageCachePolicy.GetCachedObject(DependencySourceKey);
            dependencySource.Rows.Clear();
            LoadDependencySource();
            BindDependencyGrid();

            documentSource = (DataTable) pageCachePolicy.GetCachedObject(DocumentSourceKey);
            documentSource.Rows.Clear();
            LoadDocumentSource();
            BindDocumentGrid();
        }


        /// <summary>
        /// Validates all the grids. This method is called from the control's container.
        /// </summary>
        /// <returns>true, if validation succeeded</returns>
        private bool ValidateData()
        {
            return (ValidateDependencies() && ValidateDocuments() && ValidateScripts());
        }


        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        #endregion

        #region Dependency

        /// <summary>
        /// Creates the dependencySource datatable to track changes to dependencies between questionnaire items
        /// 
        /// The dependency grid is bound to a dataview generated from the dependecySource.
        /// The SNo. column is used as a mapping column between the dependencySource and the dataview generated from the dependencySource. 
        /// The IdWhenLoaded column is used to keep track of the changes to the ChildQuestion column. If the ChildQuestion itself is changed, then 
        /// the ParentName and ParentValue fields of the question with id as in the IdWhenLoaded column must be nullified.
        /// </summary>
        private void CreateDependencySource()
        {
            dependencySource = new DataTable();
            dependencySource.Columns.Add(ColumnSNo, typeof (int));
            dependencySource.Columns.Add(ColumnId, typeof (int));
            dependencySource.Columns.Add(ColumnIdWhenLoaded, typeof (int));
            dependencySource.Columns.Add(ColumnParentQuestion);
            dependencySource.Columns.Add(ColumnParentValue);
            dependencySource.Columns.Add(ColumnChildQuestion);
            dependencySource.Columns.Add(ColumnIndent);
            dependencySource.Columns.Add(ColumnMarkForDeletion, typeof (bool));
        }


        /// <summary>
        /// Loads the dependencySource datatable with existing dependencies between questionnaire items
        /// </summary>
        private void LoadDependencySource()
        {
            int i = 0;
            foreach (QuestionnaireItem item in selectedVersion.Items)
            {
                if (!string.IsNullOrEmpty(item.ParentName))
                {
                    DataRow row = dependencySource.NewRow();
                    row[ColumnSNo] = ++i;
                    row[ColumnId] = item.Id;
                    row[ColumnIdWhenLoaded] = item.Id;
                    row[ColumnParentQuestion] = item.ParentName;
                    row[ColumnParentValue] = item.ParentValue;
                    row[ColumnChildQuestion] = item.Name;
                    row[ColumnIndent] = item.Indent;
                    row[ColumnMarkForDeletion] = false;
                    dependencySource.Rows.Add(row);
                }
            }
        }


        /// <summary>
        /// Updates the dependencySource datatable with modified values from the grid on each postback
        /// </summary>
        private void UpdateDependencySource()
        {
            DropDownList dependencyChildQuestion;
            DropDownList dependencyParentQuestion;
            DropDownList dependencyParentValue;
            CheckBox indentChild;
            for (int i = 0, itemCount = dependencyItems.Items.Count; i < itemCount; ++i)
            {
                for (int j = 0, sourceCount = dependencySource.Rows.Count; j < sourceCount; ++j)
                {
                    if (((Label) dependencyItems.Items[i].FindControl("dependencySNo")).Text == dependencySource.Rows[j][ColumnSNo].ToString())
                    {
                        dependencyChildQuestion = (DropDownList) dependencyItems.Items[i].FindControl("dependencyChildQuestion");
                        dependencyParentQuestion = (DropDownList) dependencyItems.Items[i].FindControl("dependencyParentQuestion");
                        dependencyParentValue = (DropDownList) dependencyItems.Items[i].FindControl("dependencyParentValue");
                        indentChild = (CheckBox) dependencyItems.Items[i].FindControl("indentChild");

                        dependencySource.Rows[j][ColumnParentQuestion] = (dependencyParentQuestion.SelectedIndex >= 0) ? dependencyParentQuestion.SelectedItem.Text : string.Empty;
                        dependencySource.Rows[j][ColumnParentValue] = (dependencyParentValue.SelectedIndex >= 0) ? dependencyParentValue.SelectedItem.Value : string.Empty;
                        dependencySource.Rows[j][ColumnChildQuestion] = (dependencyChildQuestion.SelectedIndex >= 0) ? dependencyChildQuestion.SelectedItem.Text : string.Empty;
                        dependencySource.Rows[j][ColumnId] = (dependencyChildQuestion.SelectedIndex >= 0) ? int.Parse(dependencyChildQuestion.SelectedValue) : 0;
                        dependencySource.Rows[j][ColumnIndent] = indentChild.Checked;
                    }
                }
            }
        }


        /// <summary>
        /// Adds a new row to the dependencySource datatable and rebinds it to the grid
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnAddDependancy(object sender, EventArgs e)
        {
            try
            {
                if (ParentItemsForDependancy.Count > 1)
                {
                    DataRow row = dependencySource.NewRow();
                    int serialNo = 0;
                    if (dependencySource.Rows.Count > 0)
                    {
                        serialNo = (int) dependencySource.Rows[dependencySource.Rows.Count - 1][ColumnSNo];
                    }
                    row[ColumnSNo] = serialNo + 1;
                    row[ColumnId] = 0;
                    row[ColumnIdWhenLoaded] = 0;
                    row[ColumnIndent] = false;
                    row[ColumnMarkForDeletion] = false;
                    dependencySource.Rows.Add(row);
                    BindDependencyGrid();
                }
                else
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Dependencies cannot be added as there are no questions which can be assigned as a parent question. At least one Radiobox question or a Checkbox question or a MultiInput question or a DropDownMultiSelect question should exist to add a Dependency";
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to add a new dependency.";
            }
        }


        /// <summary>
        /// For each of the dependencies selected for deletion, if the dependency is not present in the database(IdWhenLoaded = 0), then the 
        /// row is deleted from the dependencySource datatable. If not, the dependencySource row is marked for deletion.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnDeleteDependancy(object sender, EventArgs e)
        {
            try
            {
                for (int i = dependencyItems.Items.Count - 1; i >= 0; --i)
                {
                    CheckBox selectItem = (CheckBox) dependencyItems.Items[i].FindControl("selectDependency");
                    if (selectItem.Checked)
                    {
                        for (int j = 0, sourceCount = dependencySource.Rows.Count; j < sourceCount; ++j)
                        {
                            if (((Label) dependencyItems.Items[i].FindControl("dependencySNo")).Text == dependencySource.Rows[j][ColumnSNo].ToString())
                            {
                                if ((int) dependencySource.Rows[j][ColumnIdWhenLoaded] != 0)
                                {
                                    dependencySource.Rows[j][ColumnId] = dependencySource.Rows[j][ColumnIdWhenLoaded];
                                    dependencySource.Rows[j][ColumnMarkForDeletion] = true;
                                }
                                else
                                {
                                    dependencySource.Rows.RemoveAt(j);
                                }
                                break;
                            }
                        }
                    }
                }
                BindDependencyGrid();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to delete the selected dependencies.";
            }
        }


        /// <summary>
        /// Updates the QuestionnaireItem objects with information available in the dependencySource datatable.
        /// If the child question is different from the one that was loaded from the database, then removes the dependency for the question loaded from the database.
        /// If the dependency is marked for deletion, then remves the dependency for the child question.
        /// </summary>
        private void UpdateDependencies()
        {
            QuestionnaireItem item;
            for (int i = dependencySource.Rows.Count - 1; i >= 0; --i)
            {
                if (bool.Parse(dependencySource.Rows[i][ColumnMarkForDeletion].ToString()))
                {
                    item = selectedVersion.GetQuestionnaireItemById(int.Parse(dependencySource.Rows[i][ColumnIdWhenLoaded].ToString()));
                    item.ParentName = string.Empty;
                    item.ParentValue = string.Empty;
                    item.Indent = false;
                    dependencySource.Rows.RemoveAt(i);
                }
            }
            for (int i = dependencySource.Rows.Count - 1; i >= 0; --i)
            {
                int id = int.Parse(dependencySource.Rows[i][ColumnId].ToString());
                int idWhenLoaded = int.Parse(dependencySource.Rows[i][ColumnIdWhenLoaded].ToString());
                //clear off the dependency for old child question if the child question itselft is modified in a row
                if (idWhenLoaded != 0 && id != idWhenLoaded)
                {
                    item = selectedVersion.GetQuestionnaireItemById(idWhenLoaded);
                    item.ParentName = string.Empty;
                    item.ParentValue = string.Empty;
                    item.Indent = false;
                    dependencySource.Rows[i][ColumnIdWhenLoaded] = dependencySource.Rows[i][ColumnId];
                }
                item = selectedVersion.GetQuestionnaireItemById(id);
                item.ParentName = dependencySource.Rows[i][ColumnParentQuestion].ToString();
                item.ParentValue = dependencySource.Rows[i][ColumnParentValue].ToString();
                item.Indent = Convert.ToBoolean(dependencySource.Rows[i][ColumnIndent]);
            }
        }


        /// <summary>
        /// Binds all the non-deleted dependencies to the grid
        /// </summary>
        private void BindDependencyGrid()
        {
            DataView dependencyView = dependencySource.DefaultView;
            dependencyView.RowFilter = "MarkForDeletion = False";
            dependencyItems.DataSource = dependencyView;
            dependencyItems.DataBind();
        }


        /// <summary>
        /// Shows the selected parent and child questions. Loads parent values(item options) based on the parent questions selected.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnDependencyItemsItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    DataRowView rowView = (DataRowView) e.Item.DataItem;
                    DropDownList dependencyChildQuestion = (DropDownList) e.Item.FindControl("dependencyChildQuestion");
                    DropDownList dependencyParentQuestion = (DropDownList) e.Item.FindControl("dependencyParentQuestion");
                    DropDownList dependencyParentValue = (DropDownList) e.Item.FindControl("dependencyParentValue");
                    CheckBox indentChild = (CheckBox) e.Item.FindControl("indentChild");
                    CheckBox markForDeletion = (CheckBox) e.Item.FindControl("selectDependency");

                    dependencyParentQuestion.SelectedIndex = dependencyParentQuestion.Items.IndexOf(
                        dependencyParentQuestion.Items.FindByText(rowView[ColumnParentQuestion].ToString()));

                    if (dependencyParentQuestion.SelectedIndex > 0)
                    {
                        QuestionnaireItem questionnaireItem = selectedVersion.GetQuestionnaireItemById(int.Parse(dependencyParentQuestion.SelectedItem.Value));
                        //for multiselect and dropdownmultiselect, the child question dependencies specified are not dependent on any specific option.
                        //label and textbox do not have item options
                        if (questionnaireItem.Type != QuestionnaireItem.LabelItemType
                            && questionnaireItem.Type != QuestionnaireItem.TextBoxItemType
                                && questionnaireItem.Type != QuestionnaireItem.DropDownMultiSelectItemType
                                    && questionnaireItem.Type != QuestionnaireItem.MultiSelectItemType
                                        && questionnaireItem.Type != QuestionnaireItem.CustomValueSelectorItemType)
                        {
                            dependencyParentValue.DataSource = questionnaireItem.Options;
                            dependencyParentValue.DataTextField = "OptionValue";
                            dependencyParentValue.DataValueField = "OptionValue";
                            dependencyParentValue.DataBind();
                            dependencyParentValue.SelectedIndex = dependencyParentValue.Items.IndexOf(
                                dependencyParentValue.Items.FindByValue(rowView[ColumnParentValue].ToString()));
                            dependencyParentValue.Visible = true;
                        }
                        else
                        {
                            dependencyParentValue.Visible = false;
                        }
                    }
                    dependencyChildQuestion.SelectedIndex = dependencyChildQuestion.Items.IndexOf(
                        dependencyChildQuestion.Items.FindByText(rowView[ColumnChildQuestion].ToString()));
                    indentChild.Checked = bool.Parse(rowView[ColumnIndent].ToString());

                    if (selectedVersion.IsDeployed)
                    {
                        dependencyChildQuestion.Enabled = false;
                        dependencyParentQuestion.Enabled = false;
                        dependencyParentValue.Enabled = false;
                        markForDeletion.Enabled = false;
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to display the dependencies.";
            }
        }


        /// <summary>
        /// Loads all the options available for the parent question selected
        /// </summary>
        /// <param name="sender">The changed parent question dropdownlist</param>
        /// <param name="e">Event Arguments</param>
        protected void OnDependencyParentChanged(object sender, EventArgs e)
        {
            try
            {
                DropDownList parentQuestion = (DropDownList) sender;


                DataGridItem item = (DataGridItem) parentQuestion.Parent.Parent;
                int index = item.ItemIndex;
                DropDownList parentValue = (DropDownList) dependencyItems.Items[index].FindControl("dependencyParentValue");
                if (parentQuestion.SelectedIndex > 0)
                {
                    parentValue.DataSource = selectedVersion.GetQuestionnaireItemById(int.Parse(parentQuestion.SelectedValue)).Options;
                    BindDependencyGrid();
                }
                else
                {
                    parentValue.Items.Clear();
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load answers for the selected question.";
            }
        }


        /// <summary>
        /// Validates all the dependencies specified in the grid. Verifies that no child has multiple parents and there are no cyclic dependencies
        /// </summary>
        /// <returns>true, if each child question has one parent question and there are no cyclic dependencies</returns>
        private bool ValidateDependencies()
        {
            DataView dependencyView = dependencySource.DefaultView;
            dependencyView.RowFilter = "MarkForDeletion = False";

            //check if each child has no more than 1 parent
            for (int j = 0, count = dependencyView.Count; j < count; ++j)
            {
                string childQuestionName = dependencyView[j][ColumnChildQuestion].ToString();

                if (childQuestionName == string.Empty || dependencyView[j][ColumnParentQuestion].ToString() == string.Empty)
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Parent/Child question cannot be left blank";
                    return false;
                }
                for (int i = j + 1, viewCount = dependencyView.Count; i < viewCount; ++i)
                {
                    if (childQuestionName == dependencyView[i][ColumnChildQuestion].ToString())
                    {
                        annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                        annunciator.Message = string.Format("{0}: question has multiple parents. Cannot continue saving the QuestionnaireVersion", childQuestionName);
                        return false;
                    }
                }
            }

            //check cyclic dependencies
            for (int i = 0, viewCount = dependencyView.Count; i < viewCount; ++i)
            {
                if (CheckCyclicDependencies(dependencyView, dependencyView[i][ColumnParentQuestion].ToString(), dependencyView[i][ColumnChildQuestion].ToString()))
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Cyclic dependencies are not allowed. Cannot continue saving the QuestionnaireVersion";
                    return false;
                }
            }
            return true;
        }


        /// <summary>
        /// Checks for cyclic dependencies
        /// </summary>
        /// <param name="dependencyView">DataView containing the dependencies</param>
        /// <param name="startParentQuestionName">Name of the parent question</param>
        /// <param name="childQuestionName">Name of the child question</param>
        /// <returns>true, if cyclic dependencies are found</returns>
        private bool CheckCyclicDependencies(DataView dependencyView, string startParentQuestionName, string childQuestionName)
        {
            if (startParentQuestionName == childQuestionName)
            {
                return true;
            }
            for (int j = 0, viewCount = dependencyView.Count; j < viewCount; ++j)
            {
                if (dependencyView[j][ColumnParentQuestion].ToString() == childQuestionName)
                {
                    if (CheckCyclicDependencies(dependencyView, startParentQuestionName, dependencyView[j][ColumnChildQuestion].ToString()))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        #endregion

        #region Document

        /// <summary>
        /// Creates the documentSource datatable to track changes to documents tied to questionnaire items
        /// The SNo. column is used as a mapping column between the documentSource and the dataview generated from the documentSource. 
        /// </summary>
        private void CreateDocumentSource()
        {
            documentSource = new DataTable();
            documentSource.Columns.Add(ColumnSNo, typeof (int));
            documentSource.Columns.Add(ColumnId, typeof (int));
            documentSource.Columns.Add(ColumnItemName);
            documentSource.Columns.Add(ColumnItemValue);
            documentSource.Columns.Add(ColumnDocumentType);
            documentSource.Columns.Add(ColumnValidationMessage);
            documentSource.Columns.Add(ColumnRequired, typeof (bool));
            documentSource.Columns.Add(ColumnMarkForDeletion, typeof (bool));
        }


        /// <summary>
        /// Loads the documentSource datatable with existing documents tied to questionnaire items
        /// </summary>
        private void LoadDocumentSource()
        {
            int i = 0;
            foreach (QuestionDocument document in QuestionDocuments)
            {
                DataRow row = documentSource.NewRow();
                row[ColumnSNo] = ++i;
                row[ColumnId] = document.Id;
                row[ColumnItemName] = document.ItemName;
                row[ColumnItemValue] = document.ItemValue;
                row[ColumnDocumentType] = document.Type;
                row[ColumnValidationMessage] = document.ValidationMessage;
                row[ColumnRequired] = document.IsRequired;
                row[ColumnMarkForDeletion] = false;

                documentSource.Rows.Add(row);
            }
        }


        /// <summary>
        /// Updates the documentSource datatable with modified values from the grid on each postback
        /// </summary>
        private void UpdateDocumentSource()
        {
            for (int i = 0; i < documentItems.Items.Count; ++i)
            {
                for (int j = 0; j < documentSource.Rows.Count; ++j)
                {
                    if (((Label) documentItems.Items[i].FindControl("documentSNo")).Text == documentSource.Rows[j][ColumnSNo].ToString())
                    {
                        DropDownList documentQuestion = (DropDownList) documentItems.Items[i].FindControl("documentQuestion");
                        DropDownList documentValue = (DropDownList) documentItems.Items[i].FindControl("documentValue");
                        DropDownList documentType = (DropDownList) documentItems.Items[i].FindControl("documentType");
                        TextBox documentValidationMessage = (TextBox) documentItems.Items[i].FindControl("documentValidationMessage");
                        CheckBox documentRequired = (CheckBox) documentItems.Items[i].FindControl("documentRequired");

                        documentSource.Rows[j][ColumnItemName] = (documentQuestion.SelectedIndex >= 0) ? documentQuestion.SelectedItem.Text : string.Empty;
                        documentSource.Rows[j][ColumnItemValue] = (documentValue.SelectedIndex >= 0) ? documentValue.SelectedItem.Value : string.Empty;
                        documentSource.Rows[j][ColumnDocumentType] = (documentType.SelectedIndex >= 0) ? documentType.SelectedItem.Value : string.Empty;
                        documentSource.Rows[j][ColumnValidationMessage] = documentValidationMessage.Text.Trim();
                        documentSource.Rows[j][ColumnRequired] = documentRequired.Checked;
                    }
                }
            }
        }


        /// <summary>
        /// Adds a new row to the documentSource datatable and rebinds it to the grid
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnAddDocument(object sender, EventArgs e)
        {
            try
            {
                if (selectedVersion.Items.Count > 0)
                {
                    DataRow row = documentSource.NewRow();
                    int serialNo = (documentSource.Rows.Count > 0) ? (int) documentSource.Rows[documentSource.Rows.Count - 1][ColumnSNo] : 0;
                    row[ColumnSNo] = serialNo + 1;
                    row[ColumnId] = 0;
                    row[ColumnRequired] = false;
                    row[ColumnMarkForDeletion] = false;
                    documentSource.Rows.Add(row);
                    BindDocumentGrid();
                }
                else
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Documents cannot be added as there are no questions.";
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to add a new document.";
            }
        }


        /// <summary>
        /// For each of the documents selected for deletion, if the document is not present in the database, then the 
        /// row is deleted from the documentSource datatable. If not, the documentSource row is marked for deletion.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnDeleteDocument(object sender, EventArgs e)
        {
            try
            {
                for (int i = documentItems.Items.Count - 1; i >= 0; --i)
                {
                    if (((CheckBox) documentItems.Items[i].FindControl("selectDocument")).Checked)
                    {
                        for (int j = 0; j < documentSource.Rows.Count; ++j)
                        {
                            if (((Label) documentItems.Items[i].FindControl("documentSNo")).Text == documentSource.Rows[j][ColumnSNo].ToString())
                            {
                                if ((int) documentSource.Rows[j][ColumnId] != 0)
                                {
                                    documentSource.Rows[j][ColumnMarkForDeletion] = true;
                                }
                                else
                                {
                                    documentSource.Rows.RemoveAt(j);
                                }
                            }
                        }
                    }
                }
                BindDocumentGrid();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to delete selected document(s).";
            }
        }


        /// <summary>
        /// Updates the QuestionDocument object with information available in the documentSource datatable.
        /// </summary>
        private void UpdateDocuments()
        {
            QuestionDocument document;
            for (int i = documentSource.Rows.Count - 1; i >= 0; --i)
            {
                if (int.Parse(documentSource.Rows[i][ColumnId].ToString()) != 0)
                {
                    document = (QuestionDocument) QuestionDocuments[i];
                }
                else
                {
                    document = new QuestionDocument(cachePolicy);
                    QuestionDocuments.Add(document);
                }
                if (bool.Parse(documentSource.Rows[i][ColumnMarkForDeletion].ToString()))
                {
                    document.MarkForDelete = true;
                    documentSource.Rows.RemoveAt(i);
                }
                else
                {
                    document.ItemName = documentSource.Rows[i][ColumnItemName].ToString();
                    document.ItemValue = documentSource.Rows[i][ColumnItemValue].ToString();
                    document.Type = documentSource.Rows[i][ColumnDocumentType].ToString();
                    document.ValidationMessage = documentSource.Rows[i][ColumnValidationMessage].ToString();
                    document.IsRequired = Convert.ToBoolean(documentSource.Rows[i][ColumnRequired]);
                }
            }
        }


        /// <summary>
        /// Binds all the non-deleted documents to the grid
        /// </summary>
        private void BindDocumentGrid()
        {
            DataView documentView = documentSource.DefaultView;
            documentView.RowFilter = "MarkForDeletion = False";
            documentItems.DataSource = documentView;
            documentItems.DataBind();
        }


        /// <summary>
        /// Shows the selected question. Loads options based on the selected question.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnDocumentItemsItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    DataRowView rowView = (DataRowView) e.Item.DataItem;
                    DropDownList documentQuestion = (DropDownList) e.Item.FindControl("documentQuestion");
                    DropDownList documentValue = (DropDownList) e.Item.FindControl("documentValue");
                    DropDownList documentType = (DropDownList) e.Item.FindControl("documentType");
                    TextBox documentValidationMessage = (TextBox) e.Item.FindControl("documentValidationMessage");
                    CheckBox documentRequired = (CheckBox) e.Item.FindControl("documentRequired");
                    CheckBox markForDeletion = (CheckBox) e.Item.FindControl("selectDocument");

                    documentQuestion.SelectedIndex = documentQuestion.Items.IndexOf(
                        documentQuestion.Items.FindByText(rowView[ColumnItemName].ToString()));

                    if (documentQuestion.SelectedIndex > 0)
                    {
                        ArrayList itemOptions = selectedVersion.GetQuestionnaireItemById(int.Parse(documentQuestion.SelectedItem.Value)).Options;
                        documentValue.DataSource = itemOptions;
                        documentValue.DataTextField = "OptionValue";
                        documentValue.DataValueField = "OptionValue";
                        documentValue.DataBind();
                        documentValue.SelectedIndex = documentValue.Items.IndexOf(
                            documentValue.Items.FindByValue(rowView[ColumnItemValue].ToString()));
                    }
                    documentType.SelectedIndex = documentType.Items.IndexOf(
                        documentType.Items.FindByValue(rowView[ColumnDocumentType].ToString()));
                    documentValidationMessage.Text = rowView[ColumnValidationMessage].ToString();
                    documentRequired.Checked = bool.Parse(rowView[ColumnRequired].ToString());

                    if (selectedVersion.IsDeployed)
                    {
                        documentQuestion.Enabled = false;
                        documentValue.Enabled = false;
                        documentType.Enabled = false;
                        documentRequired.Enabled = false;
                        markForDeletion.Enabled = false;
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to display the documents.";
            }
        }


        /// <summary>
        /// Loads all the options available for the parent question selected
        /// </summary>
        /// <param name="sender">The changed parent question dropdownlist</param>
        /// <param name="e">Event Arguments</param>
        protected void OnDocumentQuestionChanged(object sender, EventArgs e)
        {
            try
            {
                DropDownList documentQuestion = (DropDownList) sender;

                DropDownList documentValue = (DropDownList) documentItems.Items[((DataGridItem) documentQuestion.Parent.Parent).ItemIndex].FindControl("documentValue");

                documentValue.DataSource = selectedVersion.GetQuestionnaireItemById(int.Parse(documentQuestion.SelectedValue)).Options;
                BindDocumentGrid();
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to load answers for the selected question.";
            }
        }

        /// <summary>
        /// Validates all the document entries.
        /// </summary>
        /// <returns></returns>
        private bool ValidateDocuments()
        {
            DataView documentView = documentSource.DefaultView;
            documentView.RowFilter = "MarkForDeletion = False";

            //check if any of the entries are blank
            for (int j = 0, count = documentView.Count; j < count; ++j)
            {
                if (documentView[j][ColumnItemName].ToString() == string.Empty)
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Document question cannot be left blank";
                    return false;
                }

                if (documentView[j][ColumnDocumentType].ToString() == string.Empty)
                {
                    annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                    annunciator.Message = "Document type cannot be left blank";
                    return false;
                }
            }


            return true;
        }

        #endregion

        #region Script

        /// <summary>
        /// Verify that no 2 scripts are of the same type 
        /// </summary>
        /// <returns>true, if no 2 scripts are of the same type</returns>
        private bool ValidateScripts()
        {
            DataView scriptView = scriptSource.DefaultView;
            scriptView.RowFilter = "MarkForDeletion = False";
            for (int j = 0, count = scriptView.Count - 1; j < count; ++j)
            {
                for (int i = j + 1, viewCount = scriptView.Count; i < viewCount; ++i)
                {
                    if (scriptView[j]["Type"].ToString() == scriptView[i]["Type"].ToString())
                    {
                        annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                        annunciator.Message = "Cannot have multiple scripts of the same type. Cannot continue saving the QuestionnaireVersion";
                        return false;
                    }
                }
            }
            return true;
        }


        /// <summary>
        /// Creates the scriptSource datatable to track changes to study persons tied to questionnaire items
        /// The SNo. column is used as a mapping column between the scriptSource and the dataview generated from the scriptSource. 
        /// </summary>
        private void CreateScriptSource()
        {
            scriptSource = new DataTable();
            scriptSource.Columns.Add(ColumnSNo, typeof (int));
            scriptSource.Columns.Add(ColumnId, typeof (int));
            scriptSource.Columns.Add("ScriptText");
            scriptSource.Columns.Add("Type");
            scriptSource.Columns.Add(ColumnMarkForDeletion);
        }


        /// <summary>
        /// Loads the scriptSource datatable with all the existing scripts
        /// </summary>
        private void LoadScriptSource()
        {
            int i = 0;
            foreach (Script script in Scripts.Values)
            {
                DataRow row = scriptSource.NewRow();
                row[ColumnSNo] = ++i;
                row[ColumnId] = script.Id;
                row["ScriptText"] = script.ScriptText;
                row["Type"] = script.Type;
                row[ColumnMarkForDeletion] = false;

                scriptSource.Rows.Add(row);
            }
        }


        /// <summary>
        /// Updates the scriptSource datatable with modified values from the grid on each postback
        /// </summary>
        private void UpdateScriptSource()
        {
            for (int i = 0, itemCount = scriptItems.Items.Count; i < itemCount; ++i)
            {
                for (int j = 0, sourceCount = scriptSource.Rows.Count; j < sourceCount; ++j)
                {
                    if (((Label) scriptItems.Items[i].FindControl("scriptSNo")).Text == scriptSource.Rows[j][ColumnSNo].ToString())
                    {
                        DropDownList scriptType = (DropDownList) scriptItems.Items[i].FindControl("scriptType");

                        scriptSource.Rows[j]["Type"] = (scriptType.SelectedIndex >= 0) ? scriptType.SelectedItem.Value : string.Empty;
                        scriptSource.Rows[j]["ScriptText"] = ((TextBox) scriptItems.Items[i].FindControl("scriptText")).Text.Trim();
                        break;
                    }
                }
            }
        }


        /// <summary>
        /// Adds a new row to the scriptSource datatable and rebinds it to the grid. The maximum number of rows
        /// that can be added to the grid is the number of available script types
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnAddScript(object sender, EventArgs e)
        {
            try
            {
                DataRow row = scriptSource.NewRow();
                row[ColumnSNo] = (scriptSource.Rows.Count > 0) ? (int) scriptSource.Rows[scriptSource.Rows.Count - 1][ColumnSNo] + 1 : 1;
                row[ColumnId] = 0;
                row[ColumnMarkForDeletion] = false;
                scriptSource.Rows.Add(row);
                BindScriptGrid();

                if (scriptItems.Items.Count == scriptTypes.Count)
                {
                    addScript.Enabled = false;
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to add a new script.";
            }
        }


        /// <summary>
        /// For each of the scripts selected for deletion, if the script is not present in the database, then the 
        /// row is deleted from the scriptSource datatable. If not, the scriptSource row is marked for deletion.
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnDeleteScript(object sender, EventArgs e)
        {
            try
            {
                for (int i = scriptItems.Items.Count - 1; i >= 0; --i)
                {
                    CheckBox selectItem = (CheckBox) scriptItems.Items[i].FindControl("selectScript");
                    if (selectItem.Checked)
                    {
                        for (int j = 0; j < scriptSource.Rows.Count; ++j)
                        {
                            if (((Label) scriptItems.Items[i].FindControl("scriptSNo")).Text == scriptSource.Rows[j][ColumnSNo].ToString())
                            {
                                if ((int) scriptSource.Rows[j][ColumnId] != 0)
                                {
                                    scriptSource.Rows[j][ColumnMarkForDeletion] = true;
                                }
                                else
                                {
                                    scriptSource.Rows.RemoveAt(j);
                                }
                                break;
                            }
                        }
                    }
                }
                BindScriptGrid();

                if (scriptItems.Items.Count < scriptTypes.Count)
                {
                    addScript.Enabled = true;
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to delete selected script(s).";
            }
        }


        /// <summary>
        /// Updates the questionnaire version's Scripts collection with information from the scriptSource datatable.
        /// </summary>
        private void UpdateScripts()
        {
            ArrayList scripts = new ArrayList();
            foreach (object o in Scripts.Values)
            {
                scripts.Add(o);
            }
            Script script = null;
            for (int i = scriptSource.Rows.Count - 1; i >= 0; --i)
            {
                int id = int.Parse(scriptSource.Rows[i][ColumnId].ToString());
                if (id != 0)
                {
                    for (int j = 0; j < scripts.Count; ++j)
                    {
                        script = (Script) scripts[j];
                        if (id == script.Id)
                        {
                            break;
                        }
                    }
                    script.MarkForDelete = bool.Parse(scriptSource.Rows[i][ColumnMarkForDeletion].ToString());
                }
                else
                {
                    script = new Script(cachePolicy);
                    scripts.Add(script);
                }
                script.ScriptText = scriptSource.Rows[i]["ScriptText"].ToString();
                script.Type = scriptSource.Rows[i]["Type"].ToString();
                script.Name = scriptSource.Rows[i]["Type"].ToString();
                if (script.MarkForDelete)
                {
                    scriptSource.Rows.RemoveAt(i);
                }
            }

            Hashtable versionScripts = new Hashtable();
            foreach (Script s in scripts)
            {
                //if the new script being added was already present but was marked for deletion
                if (versionScripts.ContainsKey(s.Type))
                {
                    Script markedForDeleteScript = (Script) versionScripts[s.Type];
                    markedForDeleteScript.Name = s.Name;
                    markedForDeleteScript.ScriptText = s.ScriptText;
                    markedForDeleteScript.MarkForDelete = false;
                }
                else
                {
                    versionScripts[s.Type] = s;
                }
            }
            Scripts = versionScripts;
        }


        /// <summary>
        /// Binds all the non-deleted scripts to the grid
        /// </summary>
        private void BindScriptGrid()
        {
            DataView scriptView = scriptSource.DefaultView;
            scriptView.RowFilter = "MarkForDeletion = False";
            scriptItems.DataSource = scriptView;
            scriptItems.DataBind();
        }


        /// <summary>
        /// Show selected script and the associated text
        /// </summary>
        /// <param name="sender">Control that raised the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnScriptItemsItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    CheckBox markForDeletion = (CheckBox) e.Item.FindControl("selectScript");
                    DataRowView rowView = (DataRowView) e.Item.DataItem;
                    DropDownList scriptType = (DropDownList) e.Item.FindControl("scriptType");
                    scriptType.DataSource = scriptTypes;
                    scriptType.DataTextField = "Meaning";
                    scriptType.DataValueField = "Code";
                    scriptType.DataBind();
                    TextBox scriptText = (TextBox) e.Item.FindControl("scriptText");
                    scriptType.SelectedIndex = scriptType.Items.IndexOf(
                        scriptType.Items.FindByValue(rowView["Type"].ToString()));
                    scriptText.Text = rowView["ScriptText"].ToString();

                    if (selectedVersion.IsDeployed)
                    {
                        scriptType.Enabled = false;
                        scriptText.ReadOnly = true;
                        markForDeletion.Enabled = false;
                    }
                }
            }
            catch
            {
                annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
                annunciator.Message = "Failed to display the scripts.";
            }
        }

        #endregion
    }
}